/**
 *
 */
package com.example.javafx.bilibilidownload.util;

import com.example.javafx.bilibilidownload.pojo.CommandResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

public final class CommandUtils {

    private static final Logger log = LogManager.getLogger(CommandUtils.class);

    private CommandUtils() {
        //
    }

    /**
     * 执行Cmd命令方法（异步读取缓冲器）
     *
     * @param command 相关命令
     * @return 执行结果
     */
    public static CommandResult runCommandAsyncReader(List<String> command, boolean flag) {
        CommandResult commandResult = new CommandResult();
        log.info("command params：" + command);
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.redirectErrorStream(true);
        Process process = null;
        try {
            process = builder.start();
            final StringBuilder stringBuilder = new StringBuilder();
            final InputStream inputStream = process.getInputStream();
            process.getOutputStream().close();
            new Thread(new Runnable() {// 启动新线程为异步读取缓冲器，防止线程阻塞
                @Override
                public void run() {
                    InputStreamReader inputStreamReader = null;
                    BufferedReader inputBufferedReader = null;
                    readBufferMessage(flag, stringBuilder, inputStream, inputStreamReader, inputBufferedReader);
                }
            }).start();
            //TODO 超时设置  process.waitFor(1000，second);
            process.waitFor();
            int exitValue = process.exitValue();
            commandResult.setExitValue(exitValue);
            commandResult.setMessage(stringBuilder.toString());
            if (flag) {
                log.info("command:{} execute Reslut:{} Message:{}", command, exitValue, commandResult.getMessage());
            }
        } catch (Exception e) {
            log.error("command Exception:" + e.getMessage(), e);
            commandResult.setExitValue(-1);
            commandResult.setMessage(e.getMessage());
        }
        return commandResult;
    }

    /**
     * 执行Cmd命令方法（同步读取缓冲器）
     *
     * @param command 相关命令
     * @return 执行结果
     */
    public static CommandResult runCommandSyncReader(List<String> command, boolean flag) {
        CommandResult commandResult = new CommandResult();
        if (flag) {
            log.info("command params：" + command);
        }
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.redirectErrorStream(true);
        Process process = null;
        try {
            process = builder.start();
            final StringBuilder stringBuilder = new StringBuilder();
            final InputStream inputStream = process.getInputStream();
            process.getOutputStream().close();
            InputStreamReader inputStreamReader = null;
            BufferedReader inputBufferedReader = null;
            readBufferMessage(flag, stringBuilder, inputStream, inputStreamReader, inputBufferedReader);
            process.waitFor();
            int exitValue = process.exitValue();
            commandResult.setExitValue(exitValue);
            commandResult.setMessage(stringBuilder.toString());
            if (flag) {
                log.info("command:{} execute Reslut:{} Message:{}", command, exitValue, commandResult.getMessage());
            }
        } catch (Exception e) {
            log.error("command Exception:" + e.getMessage(), e);
            commandResult.setExitValue(-1);
            commandResult.setMessage(e.getMessage());
        } finally {
            if (process != null) {
                process.destroy();
                if (flag) {
                    log.info("cmd process destroy");
                }
            }
        }
        return commandResult;
    }

    private static void readBufferMessage(boolean flag, StringBuilder stringBuilder, InputStream inputStream, InputStreamReader inputStreamReader, BufferedReader inputBufferedReader) {
        try {
            inputStreamReader = new InputStreamReader(inputStream);
            inputBufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = inputBufferedReader.readLine()) != null) {
                if (flag) {
                    log.info("cmd inputstream running output:{}", line);
                }
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            log.error("command IOException:" + e.getMessage(), e);
        } finally {
            if (inputBufferedReader != null) {
                try {
                    inputBufferedReader.close();
                    if (flag) {
                        log.info("cmd inputBufferedReader close");
                    }
                } catch (IOException e) {
                    log.error("command IOException:" + e.getMessage(), e);
                }
            }
            if (inputStreamReader != null) {
                try {
                    inputStreamReader.close();
                    if (flag) {
                        log.info("cmd inputStreamReader close");
                    }
                } catch (IOException e) {
                    log.error("command IOException:" + e.getMessage(), e);
                }
            }
        }
    }
}
